# -*- encoding:utf-8 -*-
"""
-文件：transaction.py
-说明：交易类
-作者：tlj
"""

import hashlib
import pickle
import random
import string
from .transaction_input import TXInput
from .transaction_output import TXOutput
from .address import Address
from .wallet import Wallets


class Transaction:
    @staticmethod
    def hash_tx(vins, vouts):
        return hashlib.sha256(pickle.dumps(vins+vouts)).hexdigest()

    def __init__(self, vins, vouts):
        self.vins = vins
        self.vouts = vouts
        self.id_ = Transaction.hash_tx(vins, vouts)  # 交易id

    def hash_(self):
        return Transaction.hash_tx(self.vins, self.vouts)

    def __repr__(self):
        return 'Transaction(id={},vins={},vouts={})'.format(
            self.id_, self.vins, self.vouts)

    def _trimmed_copy(self):
        """
        _trimmed_copy 方法拷贝了原交易对象中除了交易输入中的签名信息外的所有信息，
        生成一个原交易的拷贝对象
        :return:
        """
        inputs = []
        outputs = []

        for vin in self.vins:
            inputs.append(TXInput(vin.tx_id, vin.vout_idx,None, vin.verify_key))

        for vout in self.vouts:
            outputs.append(TXOutput(vout.address, vout.amount))

        return Transaction(inputs, outputs)

    def sign(self, sign_key):
        """
        签名
        :param sign_key:
        :return:
        """
        tx_copy = self._trimmed_copy()
        for vin_idx, vin in enumerate(tx_copy.vins):
            self.vins[vin_idx].signature = sign_key.sign(tx_copy.hash_().encode('ascii'))

    def verify(self, utxos):
        """
        交易验证
        :param uxtos: 需要验证的交易所 引用的 所有交易组成的一个字典，通过交易 ID 获取指定交易
        :return:
        """
        # for vin in self.vins:
        #     if not prev_txs[vin.tx_id].id_:
        #         print('previous transaction is not correct')

        tx_copy = self._trimmed_copy()
        for vin_idx, vin in enumerate(tx_copy.vins):
            out = utxos[vin.tx_id]
            if not out.is_locked_with(Address(vin.verify_key)):
                # 验证身份
                print("verify error:address", Address(vin.verify_key))
                return False
            sig = self.vins[vin_idx].signature
            if not vin.verify_key.verify(sig, tx_copy.hash_().encode('ascii')):
                # 签名验证
                print('verify error: signature error, ')
                return False
            # prev_tx = prev_txs[vin.tx_id]
            # if not prev_tx.vouts[vin.vout_idx].is_locked_with(Address(vin.verify_key)):
            #     # 验证身份
            #     return False
            # sig = self.vins[vin_idx].signature
            # if not vin.verify_key.verify(sig, tx_copy.hash_().encode('ascii')):
            #     # 验证签名
            #     return False
        return True


class CoinbaseTx(Transaction):
    """
    铸币交易类
    """
    subsidy = 50  # 默认挖一个块奖励50个币

    def __init__(self, to_address, tx_id=None):
        if tx_id is None:
            tx_id = ''.join(random.sample(string.ascii_letters+string.digits, 20))
        vins = [TXInput(tx_id, -1, None, None)]
        vouts = [TXOutput(to_address, CoinbaseTx.subsidy)]
        super().__init__(vins, vouts)

    def sign(self, sign_key, prev_txs):
        print("铸币交易")
        pass

    def verify(self, prev_txs):
        return True

    def __repr__(self):
        return "CoinbaseTx(id={}, vins={}, vouts={})".format(self.id_, self.vins, self.vouts)


# 未花费输出交易类 UTXOTransaction


class NotEnoughFundsError(Exception):
    pass


class UTXOTransaction(Transaction):
    # def __init__(self, from_address, to_address, amount, blockchain):
    def __init__(self, wallet, to_address, amount, utxo_set):
        """使用utxo_set代替blockchain"""
        inputs = []
        outputs = []
        from_address = wallet.address

        #acc, valid_outputs = blockchain.find_sependable_outputs(from_address, amount)
        acc, valid_outputs = utxo_set.find_spendable_outputs(from_address, amount)
        if acc < amount:
            raise NotEnoughFundsError

        # ws = Wallets()
        # # 获取钱包
        # w = ws.get_wallet(from_address.get_address_str())
        w = wallet
        # 构建交易输入列表
        for tx_id, outs in valid_outputs.items():
            # for idx, out in enumerate(outs):
            for idx in outs:
                input_ = TXInput(tx_id, idx, None, w.verify_key)
                inputs.append(input_)
        # 输出列表
        outputs.append(TXOutput(to_address, amount))
        if acc > amount:  # 找零
            outputs.append(TXOutput(from_address, acc-amount))

        super().__init__(inputs, outputs)

    def __repr__(self):
        return "UTXOTransaction(id={}, vins={}, vouts={})".format(
            self, id, self.vins, self.vouts)

